package Controller

import (
	"fmt"
	"github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
	"github.com/google/uuid"
	"github.com/jinzhu/copier"
	"log"
	"net/http"
	"time"
	"web_back_go/Common"
	"web_back_go/DAO/gorm"
	"web_back_go/DAO/gorm/GormModel"
	"web_back_go/Dto"
	"web_back_go/Middleware"
	"web_back_go/Response"
)

// userReq 用户请求参数
type userReq struct {
	UserName string `json:"userName"`
	PassWord string `json:"passWord"`
}

// Token 令牌
type Token struct {
	AccessToken  string `json:"accessToken"`
	RefreshToken string `json:"refreshToken"`
	ExpiresIn    string `json:"expiresIn"`
}

/*Register
 * @Description:  用户注册
 * @param: userReq
* @return:
*/
func Register(c *gin.Context) {
	var req userReq
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(200, gin.H{
			"code":    "A00001",
			"msg":     "请求参数有误",
			"data":    nil,
			"version": "1.0.0",
			"time":    time.Now(),
		})
		return
	}
	tx := gorm.Db.Begin()

	encrypt, err := Common.AESEncrypt([]byte(req.PassWord))
	if err != nil {
		c.JSON(200, gin.H{
			"code":    "A00001",
			"msg":     "请求参数有误",
			"data":    nil,
			"version": "1.0.0",
			"time":    time.Now(),
		})
		return
	}

	// 查询用户名是否存在
	var existingUser GormModel.TzUser
	if err := tx.Table("tz_user").Where("nick_name=?", req.UserName).First(&existingUser).Error; err == nil {
		c.JSON(200, gin.H{
			"code":    "A00001",
			"msg":     "用户名已存在，请输入其他用户名",
			"data":    nil,
			"version": "1.0.0",
			"time":    time.Now(),
		})
		return
	}

	// 插入用户数据
	user := GormModel.TzUser{
		NickName:      &req.UserName,
		LoginPassword: &encrypt,
		UserRegtime:   time.Now(),
		ModifyTime:    time.Now(),
		Status:        &[]int{1}[0], // 需要转换为指针类型
		UserId:        uuid.New().String(),
	}
	if err := tx.Table("tz_user").Create(&user).Error; err != nil {
		tx.Rollback()
		log.Println("gorm create error:", err)
		c.JSON(200, gin.H{
			"code":    "A00001",
			"msg":     "注册失败",
			"data":    nil,
			"version": "1.0.0",
			"time":    time.Now(),
		})
		return
	}
	tx.Commit()
	var Token Token
	token := Common.EncodeToken(user.UserId, req.UserName)
	Token.AccessToken = token
	Token.RefreshToken = token
	Token.ExpiresIn = "2592000"
	key := "web_auth:" + req.UserName
	cmd := Middleware.RedisClient.Set(c, key, token, time.Duration(2592000)*time.Second)
	if cmd.Err() != nil {
		log.Println("Redis set error:", cmd.Err())
		c.JSON(http.StatusOK, Response.ResponseBody{
			Code:      "A00001",
			Msg:       "服务器错误",
			Data:      nil,
			Version:   "1.0",
			Timestamp: time.Now().Unix(),
			Sign:      "",
			Success:   false,
			Fail:      true,
		})
		return
	}
	c.JSON(200, gin.H{
		"code":    "00000",
		"msg":     "注册成功",
		"data":    Token,
		"version": "1.0.0",
		"time":    time.Now(),
	})
}

/*Login
 * @Description:  用户登录
 * @param: userReq
 * @return:
 */
func Login(c *gin.Context) {
	var req userReq
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(200, gin.H{
			"code":    "A00001",
			"msg":     "请求参数有误",
			"data":    nil,
			"version": "1.0.0",
			"time":    time.Now(),
		})
		return
	}
	tx := gorm.Db.Begin()
	encrypt, err := Common.AESEncrypt([]byte(req.PassWord))
	if err != nil {
		c.JSON(200, gin.H{
			"code":    "A00001",
			"msg":     "请求参数有误",
			"data":    nil,
			"version": "1.0.0",
			"time":    time.Now(),
		})
		return
	}

	// 查询用户名是否存在
	var existingUser GormModel.TzUser
	if err := tx.Table("tz_user").Where("nick_name=?", req.UserName).First(&existingUser).Error; err != nil {
		c.JSON(200, gin.H{
			"code":    "A00001",
			"msg":     "服务器错误",
			"data":    nil,
			"version": "1.0.0",
			"time":    time.Now(),
		})
		return
	}
	if existingUser.LoginPassword == nil || *existingUser.LoginPassword != encrypt {
		c.JSON(200, gin.H{
			"code":    "A00001",
			"msg":     "账号密码错误",
			"data":    nil,
			"version": "1.0.0",
			"time":    time.Now(),
		})
		return
	}
	var Token Token
	token := Common.EncodeToken(existingUser.UserId, *existingUser.NickName)
	Token.AccessToken = token
	Token.RefreshToken = token
	Token.ExpiresIn = "2592000"
	key := "web_auth:" + *existingUser.NickName
	cmd := Middleware.RedisClient.Set(c, key, token, time.Duration(2592000)*time.Second)
	if cmd.Err() != nil {
		log.Println("Redis set error")
		c.JSON(http.StatusOK, Response.ResponseBody{
			Code:      "A00001",
			Msg:       "服务器错误",
			Data:      nil,
			Version:   "1.0",
			Timestamp: time.Now().Unix(),
			Sign:      "",
			Success:   false,
			Fail:      true,
		})
		return
	}
	c.JSON(200, gin.H{
		"code":    "00000",
		"msg":     "登录成功",
		"data":    Token,
		"version": "1.0.0",
		"time":    time.Now(),
	})
}

func ReflushToken(c *gin.Context) {
	// 获取请求头中的 Authorization 字段
	tokenString := c.GetHeader("Authorization")
	if tokenString == "" {
		c.JSON(http.StatusOK, Response.ResponseBody{
			Code:      "A00001",
			Msg:       "未提供有效的 Token",
			Data:      nil,
			Version:   "1.0.0",
			Timestamp: time.Now().Unix(),
			Sign:      "",
			Success:   false,
			Fail:      true,
		})
		return
	}

	// 解析 Token 是否有效
	token, err := jwt.ParseWithClaims(tokenString, &Common.MyClaims{}, func(token *jwt.Token) (interface{}, error) {
		return []byte("cai"), nil
	})
	if err != nil {
		c.JSON(http.StatusOK, Response.ResponseBody{
			Code:      "A00001",
			Msg:       "无效的 Token",
			Data:      nil,
			Version:   "1.0.0",
			Timestamp: time.Now().Unix(),
			Sign:      "",
			Success:   false,
			Fail:      true,
		})
		return
	}

	// 检查 Token 是否过期
	if claims, ok := token.Claims.(*Common.MyClaims); ok && token.Valid {
		if time.Now().Unix() > claims.ExpiresAt {
			// Token 已过期，生成新的 Token
			newToken := Common.EncodeToken(claims.Userid, claims.Nickname)
			if newToken == "" {
				c.JSON(http.StatusInternalServerError, Response.ResponseBody{
					Code:      "A00001",
					Msg:       "服务器错误",
					Data:      nil,
					Version:   "1.0.0",
					Timestamp: time.Now().Unix(),
					Sign:      "",
					Success:   false,
					Fail:      true,
				})
				return
			}

			// 返回新的 Token
			var Token Token
			Token.AccessToken = newToken
			Token.RefreshToken = newToken
			Token.ExpiresIn = "2592000"

			//从redis删除token
			_, UserName, _ := Common.CodeToken(tokenString)
			Middleware.RedisClient.Del(c, UserName)

			key := "web_auth:" + claims.Nickname
			cmd := Middleware.RedisClient.Set(c, key, token, time.Duration(2592000)*time.Second)
			if cmd.Err() != nil {
				log.Println("Redis set error:", cmd.Err())
				c.JSON(http.StatusOK, Response.ResponseBody{
					Code:      "A00001",
					Msg:       "服务器错误",
					Data:      nil,
					Version:   "1.0",
					Timestamp: time.Now().Unix(),
					Sign:      "",
					Success:   false,
					Fail:      true,
				})
			}
			c.JSON(http.StatusOK, Response.ResponseBody{
				Code:      "00000",
				Msg:       "刷新 Token 成功",
				Data:      Token,
				Version:   "1.0.0",
				Timestamp: time.Now().Unix(),
				Sign:      "",
				Success:   true,
				Fail:      false,
			})
		} else {
			// Token 未过期
			c.JSON(http.StatusOK, Response.ResponseBody{
				Code:      "00000",
				Msg:       nil,
				Data:      nil,
				Version:   "1.0.0",
				Timestamp: time.Now().Unix(),
				Sign:      "",
				Success:   true,
				Fail:      false,
			})
		}
	} else {
		c.JSON(http.StatusOK, Response.ResponseBody{
			Code:      "A00001",
			Msg:       "无效的 Token",
			Data:      nil,
			Version:   "1.0.0",
			Timestamp: time.Now().Unix(),
			Sign:      "",
			Success:   false,
			Fail:      true,
		})
	}
}

/*GetUserInfo
 * @Description:  获取用户信息
 * @param:
 * @return:
 */
func GetUserInfo(c *gin.Context) {
	// 获取请求头中的 Authorization 字段
	userid, err := Common.GetUserId(c)
	db := gorm.Db
	if err != nil {
		c.JSON(http.StatusOK, Response.ResponseBody{
			Code:      "A00001",
			Msg:       "服务器错误",
			Data:      nil,
			Version:   "1.0.0",
			Timestamp: time.Now().Unix(),
			Sign:      "",
			Success:   false,
			Fail:      true,
		})
		return
	}
	var user GormModel.TzUser

	if err := db.Where("user_id=?", userid).First(&user).Error; err != nil {
		c.JSON(http.StatusOK, Response.ResponseBody{
			Code:      "A00001",
			Msg:       "服务器错误",
			Data:      nil,
			Version:   "1.0.0",
			Timestamp: time.Now().Unix(),
			Sign:      "",
			Success:   false,
			Fail:      true,
		})
		return
	}
	user.LoginPassword = nil
	var userInfo Dto.UserInfoDto
	//忽略密码复制
	_ = copier.CopyWithOption(&userInfo, &user, copier.Option{IgnoreEmpty: true, DeepCopy: true})
	c.JSON(http.StatusOK, Response.ResponseBody{
		Code:      "00000",
		Msg:       nil,
		Data:      userInfo,
		Version:   "1.0.0",
		Timestamp: time.Now().Unix(),
		Sign:      "",
		Success:   true,
		Fail:      false,
	})
}

/*UpdateUserInfo
 * @Description:  更新用户信息
 */
func UpdateUserInfo(c *gin.Context) {
	var userInfo Dto.UserInfoDto

	_ = c.ShouldBindJSON(&userInfo)
	userid, err := Common.GetUserId(c)
	var user GormModel.TzUser
	_ = copier.CopyWithOption(&user, &userInfo, copier.Option{IgnoreEmpty: true, DeepCopy: true})
	db := gorm.Db.Begin()
	defer func() {
		if r := recover(); r != nil {
			db.Rollback()
			c.JSON(200, Response.ResponseBody{
				Code:    "A00005",
				Data:    nil,
				Success: true,
				Msg:     "服务器出了点小差",
			})
		} else if err != nil {
			db.Rollback()
		} else {
			db.Commit()
		}
	}()
	if userInfo.LoginPassword != nil {
		// 解引用指针得到字符串，再转换为字节切片
		plaintext := []byte(*userInfo.LoginPassword)
		encrypted, err := Common.AESEncrypt(plaintext)
		if err != nil {
			fmt.Println("加密前", userInfo.LoginPassword)
			fmt.Printf("加密出错: %v\n", err)
		} else {
			fmt.Printf("加密后的密码: %s\n", encrypted)
			user.LoginPassword = &encrypted
		}
	} else {
		fmt.Println("登录密码为空")
	}
	var oldUser GormModel.TzUser
	db.Where("user_id=?", userid).First(&oldUser)
	user.ModifyTime = time.Now()
	user.UserRegtime = oldUser.UserRegtime
	user.UserId = userid
	if *userInfo.Sex == "1" || *userInfo.Sex == "F" {
		*user.Sex = "F"
	} else {
		*user.Sex = "M"
	}

	user.Status = oldUser.Status

	plaintext := []byte(*userInfo.OldPassword)
	oldpassword, err := Common.AESEncrypt(plaintext)
	if *oldUser.LoginPassword != oldpassword {
		c.JSON(200, Response.ResponseBody{
			Code:      "A00001",
			Msg:       "原密码不正确",
			Data:      nil,
			Version:   "1.0.0",
			Timestamp: time.Now().Unix(),
			Sign:      "",
			Success:   false,
			Fail:      true,
		})
		return
	}
	db.Save(user)

	c.JSON(200, Response.ResponseBody{
		Code:      "00000",
		Msg:       nil,
		Data:      nil,
		Version:   "1.0.0",
		Timestamp: time.Now().Unix(),
		Sign:      "",
		Success:   true,
		Fail:      false,
	})
}

// UserLogout
/*
	@return token
*/
func UserLogout(c *gin.Context) {
	authHeader := c.GetHeader("Authorization")
	_, UserName, _ := Common.CodeToken(authHeader)
	Middleware.RedisClient.Del(c, UserName)
	c.JSON(200, Response.ResponseBody{
		Code:      "00000",
		Msg:       "",
		Data:      nil,
		Version:   "1.0",
		Timestamp: time.Now().Unix(),
		Sign:      "",
		Success:   true,
		Fail:      false,
	})
}
